package com.rock.upms.web.login.controller;

import java.net.URLEncoder;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.rock.common.base.BaseController;
import com.rock.common.base.BaseResult;
import com.rock.common.util.ByteUtil;
import com.rock.common.util.RedisUtil;
import com.rock.common.util.SerializeUtil;
import com.rock.common.util.StringUtil;
import com.rock.upms.api.model.service.IUpmsSystemService;
import com.rock.upms.api.model.service.IUpmsUserService;
import com.rock.upms.client.config.Global;
import com.rock.upms.client.shiro.dto.UsernamePasswordLoginTypeToken;
import com.rock.upms.client.shiro.session.UpmsSessionDao;
import com.rock.upms.client.util.UserUtil;
import com.rock.upms.model.UpmsSystemExample;
import com.rock.upms.model.dto.UserInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * 单点登录管理 Created by hotdog on 2018/1/10.
 */
@Controller
@Api(value = "登录验证")
public class SSOController extends BaseController {

	private static final Logger log = LoggerFactory.getLogger(SSOController.class);
	@Autowired
	IUpmsSystemService upmsSystemService;
	@Autowired
	IUpmsUserService upmsUserService;
	@Autowired
	UpmsSessionDao upmsSessionDao;

	@ApiOperation(value = "初始化SSO登录首页")
	@RequestMapping(value = "${adminPath}/loginInit", method = RequestMethod.GET)
	public String loginInit(HttpServletRequest request, Model model) throws Exception {
		log.trace("---> 初始化sso登录页面===begin===");
		String syscode = request.getParameter("syscode");
		String clientType = request.getParameter("clientType");
		String backurl = request.getParameter("backurl");
		if (StringUtil.isBlank(backurl)) {
			backurl = Global.getAdminPath();
		}
		// 判断请求认证系统是否注册
		UpmsSystemExample upmsSystemExample = new UpmsSystemExample();
		upmsSystemExample.createCriteria().andSystemCodeEqualTo(syscode);
		int count = upmsSystemService.countByExample(upmsSystemExample);
		if (0 == count) {
			throw new RuntimeException(String.format("未注册的系统:%s", syscode));
		}
		log.trace("---> 写入视图参数：syscode=" + syscode + ",clientType=" + clientType + ",backurl=" + backurl);
		model.addAttribute("backurl", URLEncoder.encode(backurl, "utf-8"));
		model.addAttribute("syscode", syscode);
		model.addAttribute("clientType", clientType);
		model.addAttribute("loginPageMsg", "您好！");
		log.trace("---> 初始化sso登录页面===end===");
		return "public/core/rockLogin";
	}

	/**
	 * 说明:<br>
	 * 1、sso登录入口（client和server的登录请求入口，首先进入此控制器判断）<br>
	 * 2、判断该sessionid是否有token，有则表示登录过，无则跳转到登录页面<br>
	 * 3、获取传入的backurl，有则将backurl一直往后传，无则视为server端登录，跳转到upms系统<br>
	 * 
	 * @param request
	 * @return
	 */
	@ApiOperation(value = "登录GET")
	@RequestMapping(value = "${adminPath}/login", method = RequestMethod.GET)
	public String login(HttpServletRequest request) {
		String backurl = request.getParameter("backurl");
		String syscode = request.getParameter("syscode");
		String clientType = request.getParameter("clientType");
		String loginType = request.getParameter("loginType");
		if (StringUtil.isBlank(backurl)) {
			backurl = Global.getSysSuccessUrl();
		}
		if (StringUtil.isBlank(syscode)) {
			syscode = Global.getSysCode();
		}
		if (StringUtil.isBlank(clientType)) {
			clientType = Global.getSSOClientType();
		}
		Session session = UserUtil.getSession();
		String serverSessionId = session.getId().toString();
		byte[] tokenCodeByte = RedisUtil.hget(ByteUtil.getByteKey(Global.SSO_SERVER_SESSIONID, serverSessionId), "token".getBytes());
		String tokenCode = "";
		if (tokenCodeByte != null) {
			tokenCode = (String) SerializeUtil.deserialize(tokenCodeByte);
		}
		log.trace("---->从redis中获取的tokencode：", tokenCode);
		// token校验值
		if (StringUtils.isNotBlank(tokenCode)) {
			String usercode = UserUtil.getUsercode();
			if (backurl.contains("?")) {
				backurl += "&rock_token=" + tokenCode + "&rock_usercode=" + usercode;
			} else {
				backurl += "?rock_token=" + tokenCode + "&rock_usercode=" + usercode;
			}
			log.debug("--->认证中心帐号通过，带token回跳：{}", backurl);
			return "redirect:" + backurl;
		}
		log.trace("---->未获取到token-code，重新跳转到sso登录页面,backurl=" + backurl);
		return "redirect:" + Global.getAdminPath() + "/loginInit?syscode=" + syscode + "&clientType=" + clientType + "&backurl=" + backurl;
	}

	@ApiOperation(value = "登录POST")
	@RequestMapping(value = "${adminPath}/login", method = RequestMethod.POST)
	@ResponseBody
	public BaseResult login(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) {
		String usercode = request.getParameter("usercode");
		String password = request.getParameter("password");
		String rememberMe = request.getParameter("rememberMe");
		String loginType = request.getParameter("loginType");// 登录类型
		// String backurl = request.getParameter("backurl");直接通过ajax跳转，此处不需要获取
		if (StringUtil.isBlank(usercode)) {
			return BaseResult.fail("用户名不能为空！");
		}
		if (StringUtils.isBlank(password)) {
			return BaseResult.fail("密码部门为空！");
		}
		Subject subject = SecurityUtils.getSubject();
		Session session = subject.getSession();
		String sessionId = session.getId().toString();
		// 判断是否已登录，如果已登录，则回跳，防止重复登录
		byte[] tokenCodeByte = RedisUtil.hget(ByteUtil.getByteKey(Global.SSO_SERVER_SESSIONID, sessionId), "token".getBytes());
		String tokenCode = "";
		if (tokenCodeByte != null) {
			tokenCode = (String) SerializeUtil.deserialize(tokenCodeByte);
		}
		// token校验值
		if (StringUtils.isBlank(tokenCode)) {
			// 使用shiro认证
			UsernamePasswordLoginTypeToken usernamePasswordLoginTypeToken = new UsernamePasswordLoginTypeToken(usercode, password, loginType);
			try {
				if (BooleanUtils.toBoolean(rememberMe)) {
					usernamePasswordLoginTypeToken.setRememberMe(true);
				} else {
					usernamePasswordLoginTypeToken.setRememberMe(false);
				}
				subject.login(usernamePasswordLoginTypeToken);
			} catch (UnknownAccountException e) {
				log.info("---> 登录异常：账号不存在:" + usercode);
				return BaseResult.fail("用户名或密码错误！");
			} catch (IncorrectCredentialsException e) {
				log.info("---> 登录异常：密码错误:" + usercode);
				return BaseResult.fail("用户名或密码错误！");
			} catch (LockedAccountException e) {
				log.info("---> 登录异常：账户被锁定:" + usercode);
				return BaseResult.fail("用户名或密码错误！！");
			}
			UserInfo userInfo = (UserInfo) subject.getPrincipal();
			// 默认验证帐号密码正确，创建code
			String token = UUID.randomUUID().toString();
			// 全局会话sessionId列表，供会话管理
			RedisUtil.hset(ByteUtil.getByteKey(Global.SSO_SERVER_SESSIONID, sessionId), "token".getBytes(), SerializeUtil.serialize(token));
			RedisUtil.hset(ByteUtil.getByteKey(Global.SSO_SERVER_SESSIONID, sessionId), "userInfo".getBytes(), SerializeUtil.serialize(userInfo));
			RedisUtil.expire(ByteUtil.getByteKey(Global.SSO_SERVER_SESSIONID, sessionId), (int) session.getTimeout() / 1000);
			RedisUtil.lpush(Global.SSO_SERVER_SESSIONID_LIST, sessionId);
			// code校验值
			RedisUtil.set(Global.SSO_TOKEN + token, Global.SSO_SERVER_SESSIONID + sessionId, (int) session.getTimeout() / 1000);
		}
		return BaseResult.success("");
	}


}